import asyncio
import base64
import hashlib
import hmac
import json
import time
import uuid
import websockets
from typing import Optional, Tuple, List
import os
import wave
from urllib.parse import urlencode
from datetime import datetime
from time import mktime
from wsgiref.handlers import format_date_time

from core.providers.asr.base import ASRProviderBase
from config.logger import setup_logging

TAG = __name__
logger = setup_logging()


class ASRProvider(ASRProviderBase):
    """
    讯飞语音听写（流式版）Provider
    文档: https://www.xfyun.cn/doc/asr/voicedictation/API.html
    """

    def __init__(self, config: dict, delete_audio_file: bool = True):
        super().__init__()
        self.app_id = config.get("appid")
        self.api_key = config.get("api_key")
        self.api_secret = config.get("api_secret")
        self.output_dir = config.get("output_dir")
        self.delete_audio_file = delete_audio_file

        # 从配置中获取业务参数，增加默认值
        self.language = config.get("language", "th_TH")  # 泰语
        self.domain = config.get("domain", "iat")
        # self.accent = config.get("accent", "mandarin")

        # 根据语言选择不同的Host
        if self.language in ["zh_cn", "en_us"]:
            self.HOST = "iat-api.xfyun.cn"
        else:
            self.HOST = "iat-niche-api.xfyun.cn"  # 小语种Host

        self.PATH = "/v2/iat"
        self.REQUEST_URL = f"wss://{self.HOST}{self.PATH}"

        # 确保输出目录存在
        if not os.path.exists(self.output_dir):
            os.makedirs(self.output_dir)

    def _get_auth_url(self) -> str:
        """
        生成符合讯飞语音听写V2鉴权方式的URL
        """
        # 1. 生成RFC1123格式的时间戳
        now = datetime.now()
        date = format_date_time(mktime(now.timetuple()))

        # 2. 构造签名原始字符串
        signature_origin = f"host: {self.HOST}\n"
        signature_origin += f"date: {date}\n"
        signature_origin += f"GET {self.PATH} HTTP/1.1"

        # 3. 使用hmac-sha256进行加密
        signature_sha = hmac.new(self.api_secret.encode('utf-8'), signature_origin.encode('utf-8'),
                                 digestmod=hashlib.sha256).digest()
        signature = base64.b64encode(signature_sha).decode('utf-8')

        # 4. 构造 authorization 参数
        authorization_origin = f'api_key="{self.api_key}", algorithm="hmac-sha256", headers="host date request-line", signature="{signature}"'
        authorization = base64.b64encode(authorization_origin.encode('utf-8')).decode('utf-8')

        # 5. 拼接最终请求的URL
        params = {
            "authorization": authorization,
            "date": date,
            "host": self.HOST
        }
        return self.REQUEST_URL + "?" + urlencode(params)

    async def speech_to_text(
        self, opus_data: List[bytes], session_id: str
    ) -> Tuple[Optional[str], Optional[str]]:
        """将语音数据转换为文本"""
        if not opus_data:
            logger.bind(tag=TAG).warn("音频数据为空！")
            return None, None

        file_path = None
        try:
            if not all([self.app_id, self.api_key, self.api_secret]):
                logger.bind(tag=TAG).error("讯飞语音听写配置不完整，无法进行识别")
                return None, None

            # 解码Opus为PCM
            if self.audio_format == "pcm":
                pcm_data = opus_data
            else:
                pcm_data = self.decode_opus(opus_data)
            combined_pcm_data = b"".join(pcm_data)

            if not self.delete_audio_file:
                file_path = self.save_audio_to_file(combined_pcm_data, session_id)

            auth_url = self._get_auth_url()
            
            final_result = ""
            async with websockets.connect(auth_url) as websocket:
                chunk_size = 1280  # 每次发送的音频大小
                
                # 1. 发送第一帧（包含业务参数）
                business_params = {
                    "language": self.language,
                    "domain": self.domain,
                }
                if self.language == "zh_cn":
                    business_params["accent"] = self.accent

                first_frame_data = {
                    "common": {"app_id": self.app_id},
                    "business": business_params,
                    "data": {
                        "status": 0,
                        "format": "audio/L16;rate=16000",
                        "encoding": "raw",
                        "audio": base64.b64encode(combined_pcm_data[:chunk_size]).decode('utf-8')
                    }
                }
                await websocket.send(json.dumps(first_frame_data))

                # 2. 发送中间帧
                for i in range(chunk_size, len(combined_pcm_data), chunk_size):
                    chunk = combined_pcm_data[i:i + chunk_size]
                    middle_frame_data = {
                        "data": {
                            "status": 1,
                            "format": "audio/L16;rate=16000",
                            "encoding": "raw",
                            "audio": base64.b64encode(chunk).decode('utf-8')
                        }
                    }
                    await websocket.send(json.dumps(middle_frame_data))
                    await asyncio.sleep(0.04)  # 模拟40ms的发送间隔

                # 3. 发送结束帧
                await websocket.send(json.dumps({"data": {"status": 2}}))

                # 4. 接收结果
                while True:
                    try:
                        message = await websocket.recv()
                        message_json = json.loads(message)
                        if message_json.get("code") != 0:
                            raise Exception(f"讯飞ASR返回错误: {message}")
                        
                        final_result += self._parse_result(message_json.get("data", {}))

                        if message_json.get("data", {}).get("status") == 2:
                            break
                    except websockets.exceptions.ConnectionClosed:
                        break
            
            logger.bind(tag=TAG).info(f"讯飞语音识别结果: {final_result}")
            return final_result, file_path

        except Exception as e:
            logger.bind(tag=TAG).error(f"讯飞语音识别失败: {e}", exc_info=True)
            return None, file_path

    def _parse_result(self, data: dict) -> str:
        """解析讯飞返回的JSON结果"""
        text = ""
        if "result" in data:
            ws = data["result"].get("ws", [])
            for part in ws:
                cw = part.get("cw", [])
                for word_info in cw:
                    text += word_info.get("w", "")
        return text

    def save_audio_to_file(self, pcm_data: bytes, session_id: str) -> str:
        """PCM数据保存为WAV文件"""
        module_name = __name__.split(".")[-1]
        file_name = f"asr_{module_name}_{session_id}_{uuid.uuid4()}.wav"
        file_path = os.path.join(self.output_dir, file_name)

        with wave.open(file_path, "wb") as wf:
            wf.setnchannels(1)
            wf.setsampwidth(2)
            wf.setframerate(16000)
            wf.writeframes(pcm_data)
        return file_path
